home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Language/OS - Multiplatform Resource Library
/
LANGUAGE OS.iso
/
pcr
/
pcr4_4.lha
/
DIST
/
threads
/
ThreadsKillWorld.c
< prev
next >
Wrap
C/C++ Source or Header
|
1991-06-11
|
7KB
|
288 lines
/*
* ThreadsKillWorld.c
*
* PCR System termination -- exit, panic, ThreadsTermination.
*
* Demers, December 13, 1990 10:50:00 am PST
*/
#include "xr/Errno.h"
#include "xr/ThreadsBackdoor.h"
#include "xr/ThreadsPrivate.h"
#include "xr/ThreadsMsgPrivate.h"
#include "xr/ThreadsSignalsPrivate.h"
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#include <sys/signal.h>
#include <sys/wait.h>
#define DEBUG_CLEANUP 0
/*
* panic behavior control
*/
bool XR_suspendOnPanic = TRUE;
bool
XR_GetSuspendOnPanic()
{
return XR_suspendOnPanic;
}
bool
XR_SetSuspendOnPanic(suspend)
{
bool oldValue = XR_suspendOnPanic;
XR_suspendOnPanic = suspend;
return oldValue;
}
#define MAX_PASSES 6
#define PASS_WAIT_USEC 200000
#define PANIC_STATUS 0x543210ff
/*
* Kill all siblings.
* Try to do this with XR_SIG_EXIT so they can die gracefully.
* If that fails, use SIGKILL.
*
* This proc should be called with all signals blocked.
*/
static void
XR_KillSiblings (status)
{
int i, pid, mypid, passNum, sigToSend;
bool gotOne;
extern int getpid(), kill();
mypid = getpid();
for( ((passNum = 1), (gotOne = TRUE))
; ((passNum <= MAX_PASSES) && gotOne)
; passNum++
) {
gotOne = FALSE;
sigToSend = ((passNum < MAX_PASSES) ? XR_SIG_EXIT : SIGKILL);
for( i = 0; i < XR_sysArea->sa_numIOP; i++ ) {
pid = XR_sysArea->sa_iope[i].iope_pid;
if( (pid != 0) && (pid != mypid) ) {
if( kill(pid, sigToSend) >= 0 ) gotOne = TRUE;
}
}
for( i = 0; i < XR_sysArea->sa_numVP; i++ ) {
pid = XR_sysArea->sa_vpe[i].vpe_pid;
if( (pid != 0) && (pid != mypid) ) {
if( kill(pid, sigToSend) >= 0 ) gotOne = TRUE;
}
}
pid = XR_sysArea->sa_dbpid;
if( (pid != 0) && (pid != mypid) ) {
if( kill(pid, sigToSend) >= 0 ) gotOne = TRUE;
}
if( gotOne ) {
(void)XR_SpinStep(PASS_WAIT_USEC*passNum);
while( wait3(NIL, (WNOHANG|WUNTRACED), NIL) > 0 ) {}
}
}
}
/*
*
* Exported to ThreadsTermination.h
*
* Discard all PCR resources we know about.
*
* XR_FinalCleanup should be called with no threads running,
* and on Unix stack ...
*
* The preferred way to do this is
*
* XR_longjmp(&XR_finalCleanupJmpBuf, status|0x80000000)
*
* allowing the call to be made from ThreadsInit.c
*/
/* static */ struct XR_MLRep XR_cleanupProcsLock;
typedef struct XR_CleanupProcEltRep {
struct XR_CleanupProcEltRep * cpe_next;
void (**cpe_proc)();
XR_Pointer cpe_clientData;
} * XR_CleanupProcElt;
#define N_FREE_ELTS 4
/* static */ XR_CleanupProcElt XR_cleanupProcList = NIL;
/* static */ struct XR_CleanupProcEltRep XR_cleanupProcElts[N_FREE_ELTS];
/* static */ int XR_freeCleanupProcElts =
( (sizeof XR_cleanupProcElts) / (sizeof XR_cleanupProcElts[0]) );
int
XR_RegisterTerminationCleanupProc(proc, clientData)
void (**proc)();
XR_Pointer clientData;
{
XR_CleanupProcElt cpe;
if( XR_currThread != NIL ) {
XR_MonitorEntry(&XR_cleanupProcsLock);
cpe = (XR_CleanupProcElt)XR_malloc( sizeof *cpe );
if( cpe == NIL ) { XR_SetErrno(ENOMEM); return (-1); }
} else {
if( XR_freeCleanupProcElts <= 0 )
XR_Panic("RegisterTerminationCleanupProc: out of memory");
XR_freeCleanupProcElts -= 1;
cpe = &XR_cleanupProcElts[XR_freeCleanupProcElts];
}
cpe->cpe_proc = proc;
cpe->cpe_clientData = clientData;
cpe->cpe_next = XR_cleanupProcList;
XR_cleanupProcList = cpe;
if( XR_currThread != NIL ) XR_MonitorExit(&XR_cleanupProcsLock);
return 0;
}
struct XR_JmpBufRep XR_finalCleanupJmpBuf;
void
XR_FinalCleanup(xStatus)
int xStatus;
{
XR_CleanupProcElt cpe;
for( cpe = XR_cleanupProcList; cpe != NIL; cpe = cpe->cpe_next ) {
if( (cpe->cpe_proc != NIL) && ((*(cpe->cpe_proc)) != NIL) ) {
(**(cpe->cpe_proc))(cpe->cpe_clientData);
}
}
XR_CleanUpSharedMem(); /* ??? put this on list ??? */
_exit( ((xStatus << 1) >> 1) );
}
/*
* Wait for an exit signal ... used when pausing for panic.
*/
static void
XR_WaitForExitSignal()
{
extern unsigned XR_exitSigs[];
unsigned mask, signum;
unsigned *sigp;
mask = sigblock(0);
sigp = XR_exitSigs;
while( (signum = *sigp++) != 0 ) {
mask &= (~ (sigmask(signum)) );
}
(void)sigpause(mask);
}
/*
* ExitWorld
*
* This can be called from thread or signal handler,
* on VP or IOP, sometimes recursively.
* It has to check out the state to be sure it does the
* right thing.
*/
extern int XR_localExitCnt; /* PER PROCESSOR */
void
XR_ExitWorld (status)
int status;
{
(void)sigblock(-1);
/* Make sure that the garbage collector hasn't protected */
/* any pages we care about. */
if (XR_vpe != NIL) XR_ShutDownVD();
if( XR_localExitCnt > 0 ) /* recursive entry */ return;
XR_localExitCnt += 1;
if( XR_sysArea != NIL ) {
/*
* execute mutex protocol so kill is done only once.
*/
if( XR_TestAndSet(&(XR_sysArea->sa_terminating.psl_locked)) == 0 ) {
/* got the lock, I'm responsible for doing the kill ... */
if( XR_currThread != NIL ) {
/* inhibit preemption if running in a thread */
/* (not *really* necessary because of sigblock above) */
XR_currThread->t_swStat = XR_SWSTAT_DONT_PREEMPT;
}
XR_sysArea->sa_terminationStatus = status;
XR_KillSiblings();
} else {
/* failed to get lock, somebody else will do kill ... */
XR_SpinStep(100000); /* wait for terminationStatus to appear */
_exit( XR_sysArea->sa_terminationStatus );
}
} else {
/*
* there's only one Unix process, no mutex needed
*/
;
}
/*
* Claim: exactly one process gets to this point ...
*/
if( (status == PANIC_STATUS) && XR_GetSuspendOnPanic() ) {
XR_WaitForExitSignal();
}
XR_longjmp(&XR_finalCleanupJmpBuf, (status|0x80000000) );
/*NOTREACHED*/
}
void
XR_KillWorld ()
{
XR_ExitWorld(-1);
}
int (*XR_BKS_Main_Proc)() = NIL;
void
XR_Panic(msg)
char *msg;
{
int i;
int savedErrno;
/* block all interrupts */
(void)sigblock(-1);
/* save errno */
savedErrno = XR_GetErrno(); /* works on VP or IOP! */
/* save panic message */
if( XR_sysArea != NIL ) {
XR_sysArea->sa_panicMsg = msg;
}
XR_ConsoleMsg("\n%? PANIC %s\n", msg);
XR_ConsoleMsg("%? PANIC pid %d\n", getpid());
XR_ConsoleMsg("%? PANIC errno %d\n\n", savedErrno );
/* PANIC hole for SSU Backstop */
if( XR_BKS_Main_Proc != NIL ) {
(*XR_BKS_Main_Proc)();
}
/* "halt" */
XR_ExitWorld( PANIC_STATUS );
}